﻿using System;
using System.Net.Mail;
using System.Threading.Tasks;
using GC_RF.Domain.Abstractions.Interfaces.Helpers;
using Mvc.Mailer;

namespace GC_RF.Domain.Helpers
{
	public class Mailer : MailerBase, IMailer
	{
		#region Variables

		private readonly bool _isDebug;
		private readonly string _fromtEmail;
		private readonly string _fromName;

		#endregion

		#region Constructors

		public Mailer(bool isDebug, string fromEmail, string fromName)
		{
			_isDebug = isDebug;

			if (string.IsNullOrWhiteSpace(fromEmail))
				throw new ArgumentNullException(string.Format("fromEmail"));
			_fromtEmail = fromEmail;

			if (string.IsNullOrWhiteSpace(fromName))
				throw new ArgumentNullException(string.Format("fromName"));
			_fromName = fromName;
		}

		#endregion

		#region IMailer Members

		public void SendMessageAsync(string mailTemplate, object model, string toAddress)
		{
			var message = BuildMessage(mailTemplate, model, toAddress);
			SendAsync(message);
		}

		#endregion

		#region Internal Implementation

		private MvcMailMessage BuildMessage(string mailTemplatePath, object model, string toAddress)
		{
			var message = CreateMessage(mailTemplatePath, model);
			message.To.Clear();
			message.To.Add(_isDebug ? _fromtEmail : toAddress);
			return message;
		}

		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")]
		private MvcMailMessage CreateMessage(string mailTemplatePath, object model)
		{
			var mailMessage = new MvcMailMessage { IsBodyHtml = true };
			ViewBag.Model = model;
			PopulateBody(mailMessage, mailTemplatePath);
			PopulateSubject(mailMessage);
			PopulateFrom(mailMessage);
			return mailMessage;
		}

		private void PopulateSubject(MailMessage mailMessage)
		{
			mailMessage.Subject = FindPart(mailMessage.Body, "<title>", "</title>");
		}

		private void PopulateFrom(MailMessage mailMessage)
		{
			var address = FindPart(mailMessage.Body, "<meta name=\"from\" content=\"", "\"");
			var isSystemMessage = string.IsNullOrEmpty(address);
			if (isSystemMessage)
				address = _fromtEmail;
			var displayName = FindPart(mailMessage.Body, "<meta name=\"fromName\" content=\"", "\"");
			if (string.IsNullOrEmpty(displayName) && isSystemMessage)
				displayName = _fromName;
			mailMessage.From = new MailAddress(address, displayName);
		}

		private string FindPart(string body, string start, string end)
		{
			var startIndex = body.IndexOf(start, StringComparison.OrdinalIgnoreCase);
			if (startIndex < 0)
				return null;
			startIndex += start.Length;
			var endIndex = body.IndexOf(end, startIndex, StringComparison.OrdinalIgnoreCase);
			return endIndex < 0 ? null : body.Substring(startIndex, endIndex - startIndex);
		}

		private void SendAsync(MvcMailMessage message)
		{
			try
			{
				var task = Task.Factory.StartNew(() => message.Send());
				task.ContinueWith(t =>
				{
					if (t.Exception == null) return;
					foreach (var innerEx in t.Exception.InnerExceptions)
						ApplicationLogger.Logger.LoggingExceptionMessage(innerEx);
				});
			}
			catch (Exception ex)
			{
				ApplicationLogger.Logger.LoggingExceptionMessage(ex);
			}
		}

		#endregion
	}
}